home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Diamond Collection
/
The Diamond Collection (Software Vault)(Digital Impact).ISO
/
cdr42
/
smixc111.zip
/
SMIX.C
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-15
|
22KB
|
776 lines
/* SMIXC is Copyright 1995 by Ethan Brodsky. All rights reserved */
/* █ smix.c ███████████████████████████████████████████████████████████████ */
#define TRUE 1
#define FALSE 0
#define ON 1
#define OFF 0
#define BLOCK_LENGTH 256 /* Length of digitized sound output block */
#define LOAD_CHUNK_SIZE 2048 /* Chunk size used to load sounds from disk */
#define VOICES 8 /* Number of available simultaneous voices */
/* Change VOICES at your own risk */
typedef struct
{
int xmshandle;
long startofs;
long soundsize;
} SOUND;
int init_sb(int baseio, int irq, int dma, int dma16);
/* Initializes control parameters, resets DSP and installs int. handler */
/* Parameters: */
/* baseio Sound card base IO address */
/* irq Sound card IRQ setting */
/* dma Sound card 8-bit DMA channel */
/* dma16 Sound card 16-bit DMA channel */
/* Returns: */
/* TRUE Sound card successfully initialized */
/* FALSE Sound card could not be initialized */
void shutdown_sb(void);
/* Removes interrupt handler and resets DSP */
void init_mixing(void);
/* Allocates internal buffers and starts digitized sound output */
void shutdown_mixing(void);
/* Deallocates internal buffers and stops digitized sound output */
int init_xms(void);
/* Initializes extended memory driver */
/* Returns: */
/* TRUE Extended memory driver successfully initialized */
/* FALSE Extended memory driver could not be initialized */
int getfreexms(void);
/* Returns amount of free extended memory (In kilobytes) */
void init_sharing(void);
/* Allocates an EMB that all sound data will be stored in. Using this */
/* will preserve extended memory handles, which are scarce resources. */
/* Call this on initialization and all sounds will automatically be */
/* stored in one EMB. You can call load_sound as usual to allocate a */
/* sound, but free_sound will only deallocate the sound data structure. */
/* You must call shutdown_sharing before program termination in order */
/* to free all allocated extended memory. */
void shutdown_sharing(void);
/* Shuts down EMB sharing and frees shared EMB block */
void load_sound(SOUND **sound, char *filename);
/* Allocates an extended memory block and loads a sound from a file */
/* Parameters: */
/* sound Pointer to pointer to unallocated sound data structure */
/* filename Pointer to character string containing filename */
void free_sound(SOUND **sound);
/* Frees sound data structure and extended memory block */
/* Parameters: */
/* sound Pointer to pointer to allocated sound data structure */
void start_sound(SOUND *sound, int index, int loop);
/* Starts playing a sound */
/* Parameters: */
/* sound Pointer to sound data structure */
/* index A number to keep track of the sound with (Used to stop it) */
/* loop Indicates whether sound should be continuously looped */
void stop_sound(int index);
/* Stops playing a sound */
/* Parameters: */
/* index Index of sound to stop (All with given index are stopped) */
volatile long intcount; /* Current count of sound interrupts */
volatile float dspversion; /* Version of the sound card DSP chip */
volatile int voicecount; /* Number of voices currently in use */
int autoinit;
int sixteenbit;
/* ████████████████████████████████████████████████████████████████████████ */
#include <alloc.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <mem.h>
#include "xms.h"
#define BUFFER_LENGTH BLOCK_LENGTH*2
#define BYTE unsigned char
#define lo(value) (unsigned char)((value) & 0x00FF)
#define hi(value) (unsigned char)((value) >> 8)
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) > (b)) ? (b) : (a))
int resetport;
int readport;
int writeport;
int pollport;
int poll16port;
int pic_rotateport;
int pic_maskport;
int dma_maskport;
int dma_clrptrport;
int dma_modeport;
int dma_addrport;
int dma_countport;
int dma_pageport;
int irq_startmask;
int irq_stopmask;
int irq_intvector;
int dma_startmask;
int dma_stopmask;
int dma_mode;
int shared_emb;
int shared_handle;
long shared_size;
void (interrupt far *oldintvector)(void);
int handler_installed;
void write_dsp(BYTE value)
{
while ((inp(writeport) & 0x80));
outp(writeport, value);
}
BYTE read_dsp(void)
{
while (!(inp(pollport) & 0x80));
return(inp(readport));
}
int reset_dsp(void)
{
int i;
outp(resetport, 1);
outp(resetport, 0);
i = 100;
while ((read_dsp() != 0xAA) && i--);
return(i);
}
void install_handler(void);
void uninstall_handler(void);
void mix_exitproc(void);
int init_sb(int baseio, int irq, int dma, int dma16)
{
/* Sound card IO ports */
resetport = baseio + 0x006;
readport = baseio + 0x00A;
writeport = baseio + 0x00C;
pollport = baseio + 0x00E;
poll16port = baseio + 0x00F;
/* Reset DSP, get version, choose output mode */
if (!reset_dsp())
return(0);
write_dsp(0xE1); /* Get DSP version number */
dspversion = read_dsp(); dspversion += read_dsp() / 100.0;
autoinit = (dspversion > 2.0);
sixteenbit = (dspversion > 4.0) && dma16;
/* Compute interrupt controller ports and parameters */
if (irq < 8)
{ /* PIC1 */
irq_intvector = 0x08 + irq;
pic_rotateport = 0x20;
pic_maskport = 0x21;
}
else
{ /* PIC2 */
irq_intvector = 0x70 + irq-8;
pic_rotateport = 0xA0;
pic_maskport = 0xA1;
}
irq_stopmask = 1 << (irq % 8);
irq_startmask = ~irq_stopmask;
/* Compute DMA controller ports and parameters */
if (sixteenbit)
{ /* Sixteen bit */
dma_maskport = 0xD4;
dma_clrptrport = 0xD8;
dma_modeport = 0xD6;
dma_addrport = 0xC0 + 4*(dma16-4);
dma_countport = 0xC2 + 4*(dma16-4);
switch (dma16)
{
case 5:
dma_pageport = 0x8B;
break;
case 6:
dma_pageport = 0x89;
break;
case 7:
dma_pageport = 0x8A;
break;
}
dma_stopmask = dma16-4 + 0x04; /* 000001xx */
dma_startmask = dma16-4 + 0x00; /* 000000xx */
if (autoinit)
dma_mode = dma16-4 + 0x58; /* 010110xx */
else
dma_mode = dma16-4 + 0x48; /* 010010xx */
}
else
{ /* Eight bit */
dma_maskport = 0x0A;
dma_clrptrport = 0x0C;
dma_modeport = 0x0B;
dma_addrport = 0x00 + 2*dma;
dma_countport = 0x01 + 2*dma;
switch (dma)
{
case 0:
dma_pageport = 0x87;
break;
case 1:
dma_pageport = 0x83;
break;
case 2:
dma_pageport = 0x81;
break;
case 3:
dma_pageport = 0x82;
break;
}
dma_stopmask = dma + 0x04; /* 000001xx */
dma_startmask = dma + 0x00; /* 000000xx */
if (autoinit)
dma_mode = dma + 0x58; /* 010110xx */
else
dma_mode = dma + 0x48; /* 010010xx */
}
install_handler();
shared_emb = FALSE;
atexit(mix_exitproc);
return(1);
}
void shutdown_sb(void)
{
uninstall_handler();
reset_dsp();
}
int init_xms(void)
{
xms_init();
return(xms_installed());
}
int getfreexms(void)
{
return(xms_getfreemem());
}
/* Voice control */
typedef struct
{
SOUND *sound;
int index;
long curpos;
int loop;
} VOICE;
int inuse[VOICES];
VOICE voice[VOICES];
/* Sound buffer */
signed char soundblock[BLOCK_LENGTH]; /* Signed 8 bit */
/* Mixing buffer */
short int mixingblock[BLOCK_LENGTH]; /* Signed 16 bit */
/* Output buffers */
void *outmemarea = NULL;
unsigned char (*out8buf)[2][BLOCK_LENGTH] = NULL; /* Unsigned 8 bit */
short int (*out16buf)[2][BLOCK_LENGTH] = NULL; /* Signed 16 bit */
int curblock;
void *blockptr[2];
void *curblockptr;
/* Addressing for auto-initialized transfers (Whole buffer) */
unsigned long buffer_addr;
unsigned char buffer_page;
unsigned int buffer_ofs;
/* Addressing for single-cycle transfers (One block at a time */
unsigned long block_addr[2];
unsigned char block_page[2];
unsigned int block_ofs[2];
int handler_installed;
void start_dac(void)
{
if (autoinit)
{ /* Auto init DMA */
outp(dma_maskport, dma_stopmask);
outp(dma_clrptrport, 0x00);
outp(dma_modeport, dma_mode);
outp(dma_addrport, lo(buffer_ofs));
outp(dma_addrport, hi(buffer_ofs));
outp(dma_countport, lo(BUFFER_LENGTH-1));
outp(dma_countport, hi(BUFFER_LENGTH-1));
outp(dma_pageport, buffer_page);
outp(dma_maskport, dma_startmask);
}
else
{ /* Single cycle DMA */
outp(dma_maskport, dma_stopmask);
outp(dma_clrptrport, 0x00);
outp(dma_modeport, dma_mode);
outp(dma_addrport, lo(buffer_ofs));
outp(dma_addrport, hi(buffer_ofs));
outp(dma_countport, lo(BLOCK_LENGTH-1));
outp(dma_countport, hi(BLOCK_LENGTH-1));
outp(dma_pageport, buffer_page);
outp(dma_maskport, dma_startmask);
}
if (sixteenbit)
{ /* Sixteen bit auto-initialized: SB16 and up (DSP 4.xx) */
write_dsp(0x41); /* Set sound output sampling rate */
write_dsp(hi(22050));
write_dsp(lo(22050));
write_dsp(0xB6); /* 16-bit cmd - D/A - A/I - FIFO */
write_dsp(0x10); /* 16-bit mode - signed mono */
write_dsp(lo(BLOCK_LENGTH-1));
write_dsp(hi(BLOCK_LENGTH-1));
}
else
{ /* Eight bit */
if (autoinit)
{ /* Eight bit auto-initialized: SBPro and up (DSP 2.00+) */
write_dsp(0xD1); /* Turn on speaker */
write_dsp(0x40); /* Set sound output time constant */
write_dsp(211); /* = 256 - (1000000 / rate) */
write_dsp(0x48); /* Set DSP block transfer size */
write_dsp(lo(BLOCK_LENGTH-1));
write_dsp(hi(BLOCK_LENGTH-1));
write_dsp(0x1C); /* 8-bit auto-init DMA mono output */
}
else
{ /* Eight bit single-cycle: Sound Blaster (DSP 1.xx+) */
write_dsp(0xD1); /* Turn on speaker */
write_dsp(0x40); /* Set sound output time constant */
write_dsp(211); /* = 256 - (1000000 / rate) */
write_dsp(0x14); /* 8-bit single-cycle DMA output */
write_dsp(lo(BLOCK_LENGTH-1));
write_dsp(hi(BLOCK_LENGTH-1));
}
}
}
void stop_dac(void)
{
if (sixteenbit)
{
write_dsp(0xD5); /* Pause 16-bit DMA sound I/O */
}
else
{
write_dsp(0xD0); /* Pause 8-bit DMA sound I/O */
write_dsp(0xD3); /* Turn off speaker */
}
}
/* Setup for storinng all sounds in one EMB (Saves handles) */
void init_sharing(void)
{
shared_emb = TRUE;
xms_allocate(&shared_handle, (shared_size = 0));
}
void shutdown_sharing(void)
{
if (shared_emb) xms_free(&shared_handle);
shared_emb = FALSE;
shared_handle = 0;
shared_size = 0;
}
/* Loading and freeing sounds */
void load_sound(SOUND **sound, char *filename)
{
FILE *f;
long size;
char inbuf[LOAD_CHUNK_SIZE];
long insize;
static MOVEPARAMS moveparams;
f = fopen(filename, "rb");
fseek(f, 0, SEEK_END); /* Move to end of file */
size = ftell(f); /* File size = end pos */
fseek(f, 0, SEEK_SET); /* Back to begining */
*sound = (SOUND *)malloc(sizeof(SOUND));
(*sound)->soundsize = size;
if (!shared_emb)
{
(*sound)->startofs = 0;
xms_allocate(&((*sound)->xmshandle), (size / 1024) + 1);
}
else
{
(*sound)->startofs = shared_size;
(*sound)->xmshandle = shared_handle;
shared_size += size;
xms_reallocate(shared_handle, (shared_size / 1024) + 1);
}
moveparams.sourcehandle = 0;
moveparams.sourceoffset = (long)(&inbuf);
moveparams.desthandle = (*sound)->xmshandle;
moveparams.destoffset = (*sound)->startofs;
do
{
moveparams.length = insize = fread(&inbuf, 1, sizeof(inbuf), f);
xms_move(&moveparams);
moveparams.destoffset += insize;
}
while (insize);
}
void free_sound(SOUND **sound)
{
if (!shared_emb) xms_free(&((*sound)->xmshandle));
free(*sound);
*sound = NULL;
}
/* Voice maintainance */
void deallocate_voice(int voicenum)
{
inuse[voicenum] = FALSE;
voice[voicenum].sound = NULL;
voice[voicenum].index = 0;
voice[voicenum].curpos = 0;
voice[voicenum].loop = 0;
}
void start_sound(SOUND *sound, int index, int loop)
{
int i, slot;
slot = -1; i = 0;
do
{
if (!inuse[i])
slot = i;
i++;
}
while ((slot == -1) && (i < VOICES));
if (slot != -1)
{
voice[slot].sound = sound;
voice[slot].index = index;
voice[slot].curpos = 0;
voice[slot].loop = loop;
inuse[slot] = TRUE;
++voicecount;
inuse[slot] = TRUE;
}
}
void stop_sound(int index)
{
int i;
for (i=0; i < VOICES; i++)
if (voice[i].index == index)
{
deallocate_voice(i);
--voicecount;
}
}
void update_voices(void)
{
int voicenum;
for (voicenum=0; voicenum < VOICES; voicenum++)
{
if (inuse[voicenum])
{
if (voice[voicenum].curpos >= voice[voicenum].sound->soundsize)
{
deallocate_voice(voicenum);
--voicecount;
}
}
}
}
/* Utility functions */
void setcurblock(int blocknum)
{
curblockptr = blockptr[(curblock = blocknum)];
}
void silenceblock(void)
{
memset(&mixingblock, 0x00, BLOCK_LENGTH*2);
}
long getlinearaddr(void far *ptr)
{
return((long)FP_SEG(ptr)*16 + (long)FP_OFF(ptr));
}
void init_mixing(void)
{
int i;
for (i=0; i < VOICES; deallocate_voice(i++));
voicecount = 0;
if (sixteenbit)
{
/* Find a block of memory that does not cross a page boundary */
outmemarea = malloc(4*BUFFER_LENGTH);
out16buf = outmemarea;
if ((((getlinearaddr(outmemarea) >> 1) % 65536) + BUFFER_LENGTH) > 65536)
out16buf += BUFFER_LENGTH;
for (i=0; i<2; i++) blockptr[i] = (void *)&((*out16buf)[i]);
/* DMA parameters */
buffer_addr = getlinearaddr(out16buf);
buffer_page = buffer_addr >> 16;
buffer_ofs = (buffer_addr >> 1) % 65536;
}
else
{
/* Find a block of memory that does not cross a page boundary */
outmemarea = malloc(2*BUFFER_LENGTH);
out8buf = outmemarea;
if (((getlinearaddr(outmemarea) % 65536) + BUFFER_LENGTH) > 65536)
out8buf += BUFFER_LENGTH;
for (i=0; i<2; i++) blockptr[i] = (void *)&((*out8buf)[i]);
/* DMA parameters */
buffer_addr = getlinearaddr(out8buf);
buffer_page = buffer_addr / 65536;
buffer_ofs = buffer_addr % 65536;
for (i=0; i<2; i++)
{
block_addr[i] = getlinearaddr(blockptr[i]);
block_page[i] = block_addr[i] / 65536;
block_ofs[i] = block_addr[i] % 65536;
}
}
if (sixteenbit)
memset((void *)out16buf, 0x00, BUFFER_LENGTH*2); /* Signed 16-bit */
else
memset((void *)out8buf, 0x80, BUFFER_LENGTH); /* Unsigned 8-bit */
setcurblock(0);
intcount = 0;
start_dac();
}
void shutdown_mixing(void)
{
stop_dac();
free((void *)outmemarea);
}
void copy_sound(SOUND *sound, long *curpos, int copylength, int loop)
{
long soundsize;
char far *destptr;
static MOVEPARAMS moveparams;
soundsize = sound->soundsize;
destptr = (char far *)(&soundblock);
moveparams.sourcehandle = sound->xmshandle;
moveparams.desthandle = 0;
do
{
/* Compute transfer size */
moveparams.length = min(copylength, soundsize - (*curpos));
/* Compute starting source offset and update offset for next block */
moveparams.sourceoffset = sound->startofs + (*curpos);
(*curpos) += moveparams.length;
if (loop) (*curpos) %= soundsize;
/* Compute starting dest offset and update offset for next block */
moveparams.destoffset = (long)destptr;
destptr += moveparams.length;
/* Update remaining count for next iteration (If any) */
copylength -= moveparams.length;
/* Copy block down from extended memory */
xms_move(&moveparams); /* Luckily, the XMS driver is re-entrant */
}
while (copylength > 0);
}
void mix_voice(VOICE *voice)
{
int i;
int mixlength;
if (voice->loop)
mixlength = BLOCK_LENGTH;
else
mixlength = MIN(BLOCK_LENGTH, voice->sound->soundsize - voice->curpos);
copy_sound(voice->sound, &(voice->curpos), mixlength, voice->loop);
for (i=0; i < BLOCK_LENGTH; i++)
mixingblock[i] += soundblock[i];
}
void expand_range(void)
{
int i;
for (i=0; i < BLOCK_LENGTH; i++)
mixingblock[i] <<= 5;
}
void mix_voices(void)
{
int i;
silenceblock();
for (i=0; i < VOICES; i++)
if (inuse[i]) mix_voice(&(voice[i]));
expand_range();
}
void condense16to8(void)
{
unsigned char *outptr;
int i;
outptr = &((*out8buf)[curblock][0]);
for (i=0; i < BLOCK_LENGTH; i++)
*outptr++ = (mixingblock[i] >> 8) + 0x80;
}
void copydata(void)
{
if (sixteenbit)
movmem(mixingblock, curblockptr, BLOCK_LENGTH*2);
else
condense16to8();
}
void startblock_sc(void) /* Starts a single-cycle DMA transfer */
{
outp(dma_maskport, dma_stopmask);
outp(dma_clrptrport, 0x00);
outp(dma_modeport, dma_mode);
outp(dma_addrport, lo(block_ofs[curblock]));
outp(dma_addrport, hi(block_ofs[curblock]));
outp(dma_countport, lo(BLOCK_LENGTH-1));
outp(dma_countport, hi(BLOCK_LENGTH-1));
outp(dma_pageport, block_page[curblock]);
outp(dma_maskport, dma_startmask);
write_dsp(0x14); /* 8-bit single-cycle DMA sound output */
write_dsp(lo(BLOCK_LENGTH-1));
write_dsp(hi(BLOCK_LENGTH-1));
}
void interrupt inthandler(void)
{
if (!autoinit) /* Start next block first if not using auto-init DMA */
{
startblock_sc();
copydata();
setcurblock(!curblock); /* Toggle block */
}
update_voices();
mix_voices();
if (autoinit)
{
copydata();
setcurblock(!curblock); /* Toggle block */
}
++intcount;
if (sixteenbit) /* Acknowledge interrupt with sound card */
inp(poll16port); /* 16-bit */
else
inp(pollport); /* 8-bit */
outp(0x20, 0x20); /* Acknowledge interrupt with PIC1 */
outp(0xA0, 0x20); /* Acknowledge interrupt with PIC2 */
}
void install_handler(void)
{
disable();
outp(pic_maskport, (inp(pic_maskport) | irq_stopmask));
oldintvector = _dos_getvect(irq_intvector);
_dos_setvect(irq_intvector, inthandler);
outp(pic_maskport, (inp(pic_maskport) & irq_startmask));
enable();
handler_installed = TRUE;
}
void uninstall_handler(void)
{
disable();
outp(pic_maskport, (inp(pic_maskport) | irq_stopmask));
_dos_setvect(irq_intvector, oldintvector);
enable();
handler_installed = FALSE;
}
void mix_exitproc(void)
{
outp(dma_maskport, dma_stopmask);
if (handler_installed) uninstall_handler();
}